package com.wframe.project.jnd.wx.controller;

import com.frame.database.JdataBean;
import com.github.binarywang.wxpay.bean.WxPayOrderNotifyResponse;
import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayBaseResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.wframe.project.former.enums.OrderStatusEnum;
import com.wframe.project.jnd.entity.Payment;
import com.wframe.project.jnd.rest.util.ClientException;
import com.wframe.project.jnd.rest.util.WebSession;
import com.wframe.project.jnd.services.OrderService;
import com.wframe.project.jnd.services.PayService;
import com.wframe.project.jnd.util.ServletUtils;
import com.wframe.project.jnd.wx.filter.WechatFilter;
import com.wframe.project.jnd.wx.wxImpl.WeixAccountConfig;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2017/5/12.
 */
@Controller
@RequestMapping("/we/pay")
public class WePayController {

    private static final String WE_PAY_CALLBACK = "/payment/wxNotifyBack";

    private WxMpInMemoryConfigStorage wechatMpConfig;

    private WxPayConfig wechatPayConfig;

    private WxMpService wxMpService;

    private WxPayService wxPayService;

    @Autowired
    private WeixAccountConfig tempWechatConfig;

    @Autowired
    private PayService payService;

    @Autowired
    private OrderService orderService;

    private void initWechatConfig() {
        this.wechatMpConfig = new WxMpInMemoryConfigStorage();
        this.wechatMpConfig.setAppId(this.tempWechatConfig.getAppId());
        this.wechatMpConfig.setSecret(this.tempWechatConfig.getSecret());
        this.wechatMpConfig.setToken(this.tempWechatConfig.getToken());
        this.wxMpService = new WxMpServiceImpl();
        this.wxMpService.setWxMpConfigStorage(this.wechatMpConfig);

        this.wechatPayConfig = new WxPayConfig();
        this.wechatPayConfig.setAppId(this.tempWechatConfig.getAppId());
        this.wechatPayConfig.setMchId(this.tempWechatConfig.getMch_id());
        this.wechatPayConfig.setMchKey(this.tempWechatConfig.getPayKey());
        this.wechatPayConfig.setTradeType("JSAPI");
        this.wxPayService = new WxPayServiceImpl();
        this.wxPayService.setConfig(this.wechatPayConfig);

    }

    @RequestMapping("/create")
    @ResponseBody
    public Map<String, Object> createPay(String orderType, String orderSn) {
        Map<String, Object> result = new HashMap<String, Object>();
        if (StringUtils.isNotEmpty(orderType) && StringUtils.isNotEmpty(orderSn)) {
            Payment.PayOrderType payOrderType = Payment.PayOrderType.valueOf(orderType.trim());
            Payment payment = null;
            String message = "创建支付订单失败";
            switch (payOrderType) {
                case PRODUCT_ORDER:
                    JdataBean productOrder = this.orderService.getOrderByCode(orderSn.trim());
                    if (productOrder == null) {
                        message = "商品订单不存在";
                    } else {
                        if (productOrder.getInt("paytype") != 1 || productOrder.getInt("status") != 1 || productOrder.getInt("ispay") != 0 || productOrder.getBigDecimal("pay_money") == null || productOrder.getBigDecimal("pay_money").compareTo(BigDecimal.ZERO) <= 0) {
                            message = "该商品订单不支持支付";
                        } else {
                            payment = new Payment();
                            payment.setPay_way(Payment.PayWay.WECHAT_MP);
                            payment.setOrder_type(payOrderType);
                            payment.setOrder_sn(orderSn.trim());
                            payment.setAmount(productOrder.getBigDecimal("pay_money"));
                            payment = this.payService.generateOrder(payment);
                            if (payment == null) {
                                message = "生成支付订单失败";
                            }
                        }
                    }
                    break;
                default:
                    //未找到订单类型
                    break;
            }
            if (payment != null) {
                result.put("payment", payment);
                result.put("result", "success");
                result.put("message", "创建支付订单成功");
            } else {
                result.put("result", "failure");
                result.put("message", message);
            }
            return result;
        } else {
            result.put("result", "failure");
            result.put("message", "未指定订单类型或编号");
            return result;
        }
    }

    @RequestMapping("/action")
    @ResponseBody
    public Map<String, Object> payAction(String payCode, HttpServletRequest request) {
        Payment payment = this.payService.getOrderByCode(StringUtils.trimToNull(payCode));
        WxMpUser wechatUser = (WxMpUser) request.getSession().getAttribute(WechatFilter.WECHAT_USER_KEY);
        String errorMessage = "支付失败";
        boolean orderIsPay = false;
        Map<String, Object> result = new HashMap<String, Object>();
        if (payment != null && payment.getOrder_type() == Payment.PayOrderType.PRODUCT_ORDER && payment.getOrder_sn() != null) {
            JdataBean productOrder = this.orderService.getOrderByCode(payment.getOrder_sn());
            if (productOrder == null) {
                payment = null;
            } else {
                if (productOrder.getInt("paytype") != 1 || productOrder.getInt("status") != 1 || productOrder.getInt("ispay") != 0) {
                    orderIsPay = true;
                }
            }
        }
        if (payment != null && payment.getPay_state() == Payment.PayState.GENERATED && orderIsPay == false && wechatUser != null) {
            initWechatConfig();
            try {
                StringBuffer url = request.getRequestURL();
                url.append("?");
                url.append("payCode=");
                url.append(payCode);
                WxJsapiSignature jsapiSignature = this.wxMpService.createJsapiSignature(url.toString());

                String callback = ServletUtils.buildRequestUrlPrefix(request) + WE_PAY_CALLBACK;

                WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
                orderRequest.setOutTradeNo(payment.getSn());
                orderRequest.setBody(payment.getOrder_type().toString());
                orderRequest.setTotalFee(WxPayBaseRequest.yuanToFee(payment.getAmount().toString()));
                orderRequest.setOpenid(wechatUser.getOpenId());
                orderRequest.setSpbillCreateIp(ServletUtils.getClientIP(request));
                orderRequest.setNotifyURL(callback);
                Map<String, String> payInfo = this.wxPayService.getPayInfo(orderRequest);

                result.put("result", "success");
                result.put("message", "申请微信支付成功");
                result.put("jsapi", jsapiSignature);
                result.put("payinfo", payInfo);
                result.put("payment", payment);
                return result;
            } catch (WxErrorException e) {
                e.printStackTrace();
                errorMessage = e.getMessage() + " ";
                int errorStartIndex = -1;
                int errorEndIndex = errorMessage.length();
                String searchWord = "错误详情：";
                String splitWord = "，";
                if ((errorStartIndex = StringUtils.lastIndexOf(errorMessage, searchWord)) >= 0) {
                    if (StringUtils.indexOf(errorMessage, splitWord, errorStartIndex) > errorStartIndex) {
                        errorEndIndex = StringUtils.indexOf(errorMessage, splitWord, errorStartIndex);
                    }
                    errorMessage = errorMessage.substring(errorStartIndex + searchWord.length(), errorEndIndex).trim();
                }
                result.put("result", "failure");
                result.put("message", errorMessage);
                return result;
            }
        } else {
            if (payment == null) {
                errorMessage = "支付订单不存在：" + payCode;
            }
            if (orderIsPay) {
                errorMessage = "该交易已支付";
            }
            if (wechatUser == null) {
                errorMessage = "未获取到微信用户信息";
            }
            if (payment.getPay_state() != Payment.PayState.GENERATED) {
                errorMessage = "该支付订单已处理";
            }
            result.put("result", "failure");
            result.put("message", errorMessage);
            return result;
        }
    }

    @RequestMapping("/result/{result}")
    public String showPayResult(@PathVariable("result") String result, String paySn, String cod , String orderType , String orderSn , String message, Model model, HttpSession session) {
        Payment payment = this.payService.getOrderByCode(StringUtils.trimToEmpty(paySn));
        if ("success".equalsIgnoreCase(result)) {
            if (!WebSession.checkLoginStatus(session)) {
                return "/wesite/view/sign/login";
            }
            model.addAttribute("message", message);
            model.addAttribute("payment", payment);
            model.addAttribute("cod", cod);
            model.addAttribute("orderType", orderType);
            model.addAttribute("orderSn", orderSn);
            return "/wesite/view/pay/pay-success";
        } else if ("fail".equalsIgnoreCase(result) || "failure".equalsIgnoreCase(result)) {
            if (!WebSession.checkLoginStatus(session)) {
                return "/wesite/view/sign/login";
            }
            model.addAttribute("message", message);
            model.addAttribute("payment", payment);
            model.addAttribute("cod", cod);
            model.addAttribute("orderType", orderType);
            model.addAttribute("orderSn", orderSn);
            return "/wesite/view/pay/pay-failure";
        } else {
            return null;
        }
    }

    @RequestMapping("/way")
    public String payWay(String orderType, String orderSn, Model model, HttpSession session) {
        if (!WebSession.checkLoginStatus(session)) {
            return "/wesite/view/sign/login";
        }
        Payment.PayOrderType payOrderType = Payment.PayOrderType.valueOf(StringUtils.trimToEmpty(orderType));
        String payOrderSn = StringUtils.trimToEmpty(orderSn);
        if (payOrderType != null) {

            switch (payOrderType) {
                case PRODUCT_ORDER:
                    JdataBean jdataBean = this.orderService.getOrderByCode(payOrderSn);
                    if (jdataBean != null) {
                        model.addAttribute("payOrderType", payOrderType);
                        model.addAttribute("payOrderSn", payOrderSn);
                        model.addAttribute("payAmount", jdataBean.getBigDecimal("pay_money"));
                        return "/wesite/view/pay/pay-way";
                    }
                    break;
            }

        }
        return null;
    }

    @RequestMapping("/way/cod")
    public String payWayCod(HttpServletRequest request, String orderType, String orderSn, Model model) throws UnsupportedEncodingException {
        Payment.PayOrderType payOrderType = Payment.PayOrderType.valueOf(StringUtils.trimToEmpty(orderType));
        String payOrderSn = StringUtils.trimToEmpty(orderSn);
        String urlPrefix = ServletUtils.buildRequestUrlPrefix(request);
        String message = "选择货到付款失败";
        if (payOrderType != null) {
            switch (payOrderType) {
                case PRODUCT_ORDER:
                    JdataBean order = this.orderService.getOrderByCode(payOrderSn);
                    if (order != null) {
                        if (order.getInt("status") != 1 || order.getInt("paytype") != 1) {
                            message = "订单" + payOrderSn + "当前状态不支持此操作：status:" + order.getInt("status") + ",paytype:" + order.getInt("paytype");
                        } else {
                            Map columnMap = new HashMap();
                            Map keyMap = new HashMap();
                            keyMap.put("code", payOrderSn);
                            columnMap.put("paytype", 2);
                            columnMap.put("status", OrderStatusEnum.Confirm.getStatus());
                            orderService.update(columnMap, keyMap);
                            message = "选择货到付款成功";
                            return "redirect:" + urlPrefix + "/we/pay/result/success?cod=true&orderType="+payOrderType+"&orderSn="+payOrderSn+"&message=" + URLEncoder.encode(message, "UTF-8");
                        }
                    } else {
                        message = "未找到商品订单：" + payOrderSn;
                    }
                    break;
                default:
                    message = "未实现的订单类型：" + orderType;
                    break;
            }
        } else {
            message = "不支持的订单类型：" + orderType;
        }
        return "redirect:" + urlPrefix + "/we/pay/result/fail?cod=true&orderType="+payOrderType+"&orderSn="+payOrderSn+"&message=" + URLEncoder.encode(message, "UTF-8");
    }

}
